<script lang="ts" setup>
import type { IMenu } from '../store/menu'
import {
  bus,
  Tree,
} from '@pkgs/utils'
import {
  useBattery,
  useDark,
  useDocumentVisibility,
  useOnline,
  useTitle,
} from '@vueuse/core'
import { ElMessageBox } from 'element-plus'
import { isEmpty } from 'lodash-es'
import { defineStore } from 'pinia'
import { EventName } from '../enums'
import {
  APP_URL_MAP,
  MAIN_APP_SLOT_ROUTE_PATH,
} from '../settings'
import useAppStore from '../store/app'
import useAuthStore from '../store/auth'
import useConfigStore from '../store/config'
import useLocaleStore from '../store/locale'
import useMenuStore from '../store/menu'
import useMicroStore from '../store/micro'
import useProjectStore from '../store/project'
import useTabStore from '../store/tab'
import {
  getRouter,
  isMicro,
} from '../utils'
import AppAside from './components/app-aside/index.vue'
import AppHeader from './components/app-header/index.vue'
import AppLogo from './components/app-logo/index.vue'
import AppTab from './components/app-tab/index.vue'
import Setting from './components/setting/index.vue'

const state = reactive({
  isCollapse: false,
  lock: false,
})

const route = useRoute()
// const router = useRouter()
const router = getRouter()
const i18n = useI18n()
const online = useOnline()
const { level } = useBattery()
const isDark = useDark()

const microStore = useMicroStore()
const projectStore = useProjectStore()
const appStore = useAppStore()
const menuStore = useMenuStore()
const authStore = useAuthStore()
const tabStore = useTabStore()
const localeStore = useLocaleStore()
const configStore = useConfigStore()

const customStyle = computed(() => {
  return { '--aside-width': state.isCollapse ? '60px' : '240px' }
})

const appUrl = computed(() => {
  const url = `${APP_URL_MAP[appStore.getAppCode][import.meta.env.VITE_ENV]}`
  return url
})

const isFullscreen = computed(() => {
  return tabStore.currentTab?.fullscreen
})

const watermarkText = computed(() => {
  return configStore.watermark ? authStore.userInfo.name : ''
})

function jumpApp({
  projectCode,
  appCode,
  menuCode,
  menuName,
  path,
  query = {},
}: { projectCode: string, appCode: string, menuCode?: string, menuName?: string, path: string, query?: Record<string, any> }) {
  if (projectCode === projectStore.getProjectCode && appCode === appStore.getAppCode) {
    let _path = `${MAIN_APP_SLOT_ROUTE_PATH}/${projectCode}/${appCode}${path}`

    if (!isEmpty(query)) {
      const queryStr = new URLSearchParams(query).toString()
      _path += `?${queryStr}`
    }

    router.push({ path: _path })

    if (menuCode) {
      const menu = new Tree<IMenu>().findNode(menuStore.getMenus, node => node.code === menuCode)
      tabStore.addTab(menu)
    }
    else {
      if (!menuName)
        return

      tabStore.addTab({
        name: menuName,
        code: `${projectCode}_${appCode}_${menuCode}`,
        projectCode,
        appCode,
        path,
      } as any)
    }
  }
}

function notifySubAppRouteChange() {
  const pathPrefix = `${import.meta.env.VITE_PUBLIC_PATH}${MAIN_APP_SLOT_ROUTE_PATH}/${projectStore.getProjectCode}/${appStore.getAppCode}`
  const {
    pathname,
    search,
  } = location
  const subAppRoutePath = pathname.replace(pathPrefix, '')

  bus.emit(EventName.SUB_ROUTE_CHANGE, {
    appCode: appStore.getAppCode,
    path: subAppRoutePath + search,
  })

  const menu = new Tree<IMenu>().findNode(menuStore.getMenus, node => node.path === subAppRoutePath)
  tabStore.addTab(menu || menuStore.getMenus[0])
}

function currentAppRouteChange() {
  const pathPrefix = `${import.meta.env.VITE_PUBLIC_PATH}`
  const { pathname } = location
  const subAppRoutePath = pathname.replace(pathPrefix, '')

  const menu = new Tree<IMenu>().findNode(menuStore.getMenus, node => node.path === subAppRoutePath)

  tabStore.addTab(menu || menuStore.getMenus[0])
}

watch(() => tabStore.getCurrentTabCode, (currentTabCode) => {
  if (!currentTabCode)
    return

  state.lock = true

  if (isMicro(route.path)) {
    microStore.getBus.emit(EventName.SUB_ROUTE_CHANGE, {
      appCode: tabStore.currentTab!.appCode,
      path: tabStore.currentTab!.path,
      query: tabStore.currentTab?.query ?? {},
    })

    const { getProjectCode } = useProjectStore()
    const { getAppCode } = useAppStore()

    let path = tabStore.currentTab?.path
    const query = tabStore.currentTab?.query

    if (!isEmpty(query)) {
      const queryStr = new URLSearchParams(query).toString()
      path += `?${queryStr}`
    }

    if (path) {
      router.push({ path: `${MAIN_APP_SLOT_ROUTE_PATH}/${getProjectCode}/${getAppCode}${path}` })
    }
  }
  else {
    if (!tabStore.currentTab?.path)
      return

    router.push({
      path: `${tabStore.currentTab!.path}`,
      query: tabStore.currentTab?.query ?? {},
    })
  }

  state.lock = false
}, { immediate: true })

watch(() => route.path, (path) => {
  if (state.lock)
    return

  if (isMicro(path)) {
    notifySubAppRouteChange()
  }
  else {
    currentAppRouteChange()
  }
}, { immediate: true })

watch(online, (online) => {
  if (!online) {
    const visibility = useDocumentVisibility()
    if (toValue(visibility) === 'visible') {
      ElMessageBox.alert(
        '您的网络已经断开，请检查网络连接！',
        '提示',
        { confirmButtonText: '我知道了' },
      )
    }
  }
})

watchEffect(() => {
  if (toValue(level) < 0.05) {
    ElMessageBox.alert(
      '您的设备电量过低,不足5%，请及时充电！',
      '提示',
      { confirmButtonText: '我知道了' },
    )
  }
})

onMounted(() => {
  if (isMicro(route.path)) {
    bus.on(EventName.SUB_APP_LOADED, () => {
      setTimeout(() => {
        notifySubAppRouteChange()
      }, 0)
    })
  }
  else {
    currentAppRouteChange()
  }
})
</script>

<template>
  <ElWatermark
    :content="watermarkText"
    :z-index="1"
    :font="{
      fontSize: 10,
      color: isDark ? 'rgba(255, 255, 255,.15)' : 'rgba(0, 0, 0, .15)',
    }"
    :gap="[150, 150]"
  >
    <div
      class="layout"
      :class="configStore.getLayoutType"
      :style="customStyle"
    >
      <AppAside
        class="layout__aside"
        :is-collapse="state.isCollapse"
      />

      <AppLogo
        class="layout__logo"
        :is-collapse="state.isCollapse"
      />

      <AppHeader
        v-model:is-collapse="state.isCollapse"
        class="layout__header"
      />

      <AppTab class="layout__tab" />

      <div
        class="layout__main-wrapper"
        :class="[
          { fullscreen: isFullscreen },
        ]"
      >
        <div class="layout__main">
          <slot>
            <WujieVue
              v-if="isMicro(route.path)"
              width="100%"
              height="100%"
              :name="appStore.getAppCode"
              :url="appUrl"
              :props="{
                bus,
                token: authStore.getToken,
                menus: menuStore.getMenus,
                language: localeStore.getLanguage,
                getLanguage: () => localeStore.getLanguage,
                locale: localeStore.getLocale,
                getLocale: () => localeStore.getLocale,
                jump: jumpApp,
                setTitle: useTitle,
                $t: i18n.t,
                deleteToken: authStore.deleteToken,
                defineStore,
              }"
            />

            <RouterView
              v-else
              v-slot="{ Component: C }"
            >
              <KeepAlive>
                <Component :is="C" />
              </KeepAlive>
            </RouterView>
          </slot>
        </div>
      </div>

      <Setting v-if="!isFullscreen" />
    </div>
  </ElWatermark>
</template>

<style lang="less" scoped>
.layout,
.layout.one {
  display: grid;
  --aside-min-width: 150px;
  --header-height: 48px;
  --tab-height: 39px;
  --main-height: calc(100vh - var(--header-height) - var(--tab-height));

  grid-template-areas:
    'logo header'
    'aside tab'
    'aside main';
  grid-template-columns: var(--aside-width) 1fr;
  grid-template-rows: var(--header-height) var(--tab-height) var(--main-height);
  min-block-size: 100vh;
  transition: grid-template-columns 0.3s ease-in-out;

  &__aside {
    grid-area: aside;
    transition: inline-size 0.3s ease-in-out;
  }

  &__logo {
    grid-area: logo;
  }

  &__header {
    grid-area: header;
  }

  &__tab {
    overflow: auto;
    grid-area: tab;
  }

  &__main {
    position: relative;
    z-index: 0;
    block-size: 100%;

    &-wrapper {
      overflow-y: auto;
      background-color: var(--el-bg-color-page);
      grid-area: main;
      scroll-behavior: smooth;

      &.fullscreen {
        padding: 0;
        z-index: 99;
        grid-area: 1 / 1 / -1 / -1;
      }
    }
  }
}

.layout.two {
  --main-height: calc(100vh - var(--header-height));
  grid-template-areas:
    'logo header'
    'aside main';
  grid-template-rows: var(--header-height) var(--main-height);

  .layout__tab {
    display: none;
  }
}

.layout.three {
  --main-height: calc(100vh - var(--header-height));
  grid-template-areas:
    'logo header'
    'main main';
  grid-template-rows: var(--header-height) var(--main-height);
  grid-template-columns: 126px 1fr;

  .layout__tab {
    display: none;
  }

  .layout__aside {
    display: none;
  }
}

.layout.four {
  grid-template-areas:
    'logo header'
    'tab tab'
    'main main';
  grid-template-columns: 126px 1fr;

  .layout__aside {
    display: none;
  }
}
</style>
